package com.mystudio.android.calendar.util;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.ContentUris;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;

import com.mystudio.android.calendar.constants.Constants;
import com.mystudio.android.calendar.model.Calendar;
import com.mystudio.android.calendar.model.Instance;
import com.mystudio.android.util.Logger;

// Util for sync calendar data via google calendar content provider
public class CPSyncUtil {
	private static final Logger logger = new Logger(Constants.LOG_TAG, CPSyncUtil.class);

	private static final String CLASS_ANDROID_CALENDARS = "android.provider.Calendar$Calendars";
	//private static final String CLASS_ANDROID_EVENTS = "android.provider.Calendar$Events";
	private static final String CLASS_ANDROID_INSTANCES = "android.provider.Calendar$Instances";

	private static final String CLASS_ANDROID_CALENDARS_COLUMNS = "android.provider.Calendar$CalendarsColumns";
	private static final String CLASS_ANDROID_EVENTS_COLUMNS = "android.provider.Calendar$EventsColumns";
	
	private static Uri CALENDARS_CONTENT_URI = null;
	//private static Uri EVENTS_CONTENT_URI = null;
	private static Uri INSTANCES_CONTENT_URI = null;
	
	// Calendars columns
	private static String COL_DISPLAY_NAME = null;
	private static String COL_SELECTED = null;
	private static String COL_COLOR = null;

	// Events, instances columns
	private static String COL_CALENDAR_ID = null;
	private static String COL_EVENT_ID = null;
	private static String COL_TITLE = null;
	private static String COL_DESC = null;
	private static String COL_ALL_DAY = null;
	private static String COL_BEGIN = null;
	private static String COL_END = null;
	private static String COL_START_DAY = null;
	private static String COL_END_DAY = null;
	
	private static CPSyncUtil instance = null;
	
	private CPSyncUtil() {
	}
	
	public static CPSyncUtil getInstance() {
		if (instance == null) {
			instance = new CPSyncUtil();
		}
		
		return instance;
	}
	
    private void initContentProviderConstants() {
    	if (CALENDARS_CONTENT_URI == null || INSTANCES_CONTENT_URI == null) {
	    	try {
		        Class<?> androidClass;
		        
		        androidClass = Class.forName(CLASS_ANDROID_CALENDARS); 
		        CALENDARS_CONTENT_URI = (Uri)androidClass.getField("CONTENT_URI").get(null); 
		        COL_DISPLAY_NAME = (String)androidClass.getField("DISPLAY_NAME").get(null);
		        COL_COLOR = (String)androidClass.getField("COLOR").get(null);

		        androidClass = Class.forName(CLASS_ANDROID_CALENDARS_COLUMNS); 
		        COL_SELECTED = (String)androidClass.getField("SELECTED").get(null);

		        androidClass = Class.forName(CLASS_ANDROID_INSTANCES); 
		        INSTANCES_CONTENT_URI = (Uri)androidClass.getField("CONTENT_URI").get(null); 
		        COL_EVENT_ID = (String)androidClass.getField("EVENT_ID").get(null);
		        COL_BEGIN = (String)androidClass.getField("BEGIN").get(null);
		        COL_END = (String)androidClass.getField("END").get(null);
		        COL_START_DAY = (String)androidClass.getField("START_DAY").get(null);
		        COL_END_DAY = (String)androidClass.getField("END_DAY").get(null);
		        
		        //androidClass = Class.forName(CLASS_ANDROID_EVENTS); 
		        //URI_EVENTS_CONTENT_PROVIDER = (Uri)androidClass.getField("CONTENT_URI").get(null); 
		        
		        androidClass = Class.forName(CLASS_ANDROID_EVENTS_COLUMNS);
		        COL_CALENDAR_ID = (String)androidClass.getField("CALENDAR_ID").get(null);
		        COL_TITLE = (String)androidClass.getField("TITLE").get(null);
		        COL_DESC = (String)androidClass.getField("DESCRIPTION").get(null);
		        COL_ALL_DAY = (String)androidClass.getField("ALL_DAY").get(null);

	    	} catch (Exception e) {
	    		logger.error("Cannot identify calendar content provider URIs", e);
	    	}
    	}
    	if (CALENDARS_CONTENT_URI != null) {
    		logger.info("Calendars URI: " + CALENDARS_CONTENT_URI.toString()); 
    	} else {
    		logger.warn("Unable to get URI for calendars content provider");
    	}
    	if (INSTANCES_CONTENT_URI != null) {
    		logger.info("Instances URI: " + INSTANCES_CONTENT_URI.toString()); 
    	} else {
    		logger.warn("Unable to get URI for instances content provider");
    	}
    }
    
    private Uri getCalendarsUri() {
    	if (CALENDARS_CONTENT_URI == null) {
    		initContentProviderConstants();
    	}
    	
    	return CALENDARS_CONTENT_URI;
    }
    
    private Uri getInstancesUri() {
    	if (INSTANCES_CONTENT_URI == null) {
    		initContentProviderConstants();
    	}
    	
    	return INSTANCES_CONTENT_URI;
    }
    
    public List<Calendar> getSelectedCalendars(Activity activity) {
    	return getCalendars(activity, true);
    }
    
    public List<Calendar> getCalendars(Activity activity, boolean selected) {
    	List<Calendar> calendars = null;
    	String selection = selected?COL_SELECTED +"=1":"";
    	
    	if (getCalendarsUri() != null) {
    		Cursor managedCursor = null;
			try {
				managedCursor = activity.getContentResolver().query(
						getCalendarsUri(), 
					new String[] {BaseColumns._ID, COL_DISPLAY_NAME, COL_COLOR}, 
					selection,       
					null,
					null);
				calendars = new ArrayList<Calendar>();
				if (managedCursor.moveToFirst()) {
					do {    
						Calendar calendar = new Calendar(managedCursor.getString(0));
						calendar.setDisplayName(managedCursor.getString(1));
						calendar.setColor(managedCursor.getInt(2));
						calendars.add(calendar);
					} while (managedCursor.moveToNext());
				}
			} catch (Exception e) {
				logger.error("Failed to get calendar list", e);
				calendars = null;
			} finally {
				if (managedCursor != null) {
					managedCursor.close();
					managedCursor = null;
				}
			}
    	}
    	
    	return calendars;
    }
    
    public List<Instance> getInstancesInThisMonth(Activity activity, List<Calendar> calendars) {
    	java.util.Calendar calendar = java.util.Calendar.getInstance(); 
    	calendar.set(java.util.Calendar.DATE, 1);
    	calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
    	calendar.set(java.util.Calendar.MINUTE, 0);
    	calendar.set(java.util.Calendar.SECOND, 0);
    	calendar.set(java.util.Calendar.MILLISECOND, 0);
    	
    	long begin = calendar.getTime().getTime();
    	calendar.add(java.util.Calendar.MONTH, 1);
    	long end = calendar.getTime().getTime()-1;

    	//logger.info("start: " + begin + ":" + SimpleDateFormat.getDateTimeInstance().format(begin));
    	//logger.info("end: " + end + ":" + SimpleDateFormat.getDateTimeInstance().format(end));
    	
    	return getInstances(activity, calendars, begin, end);
    }
    
    public List<Instance> getInstances(Activity activity, List<Calendar> calendars, long begin, long end) {
    	List<Instance> eventInstances = new ArrayList<Instance>();
logger.info("URI: " + CALENDARS_CONTENT_URI + " : " + INSTANCES_CONTENT_URI);
    	if (getInstancesUri() != null && calendars != null && calendars.size() > 0) {
    		Cursor managedCursor = null;
	    	try {
		    	String[] projection = new String[] {
		    			COL_EVENT_ID, COL_CALENDAR_ID, COL_TITLE, COL_DESC, COL_BEGIN, COL_END, COL_COLOR, COL_START_DAY, COL_END_DAY, COL_ALL_DAY};
		    	
	            Uri.Builder builder = getInstancesUri().buildUpon();
	            ContentUris.appendId(builder, begin);
	            ContentUris.appendId(builder, end);
	            Uri uri = builder.build();
	            
	            StringBuffer calendarsWhere = new StringBuffer("Calendars._id=" + calendars.get(0).getId());
	            for (int i=1; i<calendars.size(); ++i) {
	            	calendarsWhere.append(" or Calendars._id=" + calendars.get(i).getId());
	            }
logger.info("CPSyncUtil: " + uri + ":" + projection + ":" + calendarsWhere.toString());
	            managedCursor = activity.getContentResolver().query(
		    		uri, 
		    		projection, 
		    		calendarsWhere.toString(),       
		    		null,
		    		"startDay ASC, startMinute ASC");
		    	
		    	if (managedCursor != null && managedCursor.moveToFirst()) {
		    		do {    
		    			Instance eventInstance = new Instance();
		    			eventInstance.eventId = managedCursor.getString(0);
		    			eventInstance.calendarId = managedCursor.getString(1);
		    			eventInstance.title = managedCursor.getString(2);
		    			eventInstance.description = managedCursor.getString(3);
		    			eventInstance.begin = managedCursor.getString(4);
		    			eventInstance.end = managedCursor.getString(5);
		    			eventInstance.color = managedCursor.getInt(6);
		    			eventInstance.startDay = managedCursor.getInt(7);
		    			eventInstance.endDay = managedCursor.getInt(8);
		    			eventInstance.allDay = managedCursor.getString(9);
		    			eventInstances.add(eventInstance);
		    		
		    		} while (managedCursor.moveToNext());
		    	}
	    	} catch (Exception e) {
	    		logger.error("Failed to get calendar list", e);
	    		eventInstances = null;
	    	} finally {
	    		if (managedCursor != null) {
	    			managedCursor.close();
	    			managedCursor = null;
	    		}
	    	}
    	}
    	
    	return eventInstances;
    }
}
